package mts.testframework;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;

import mts.ElevatorControllerInternalConnectionServer;
import mts.groupdispatcher.GroupDispatcher;
import mts.testframework.testitems.FloorRequestTestItem;
import mts.testframework.testitems.HallCallTestItem;
import mts.testframework.testitems.TestItem;


public class TestItemScheduler {
	
	// nasty but we are on tight time constraints
	String output = "All times below are in milliseconds\n\nPerson Metric Value\n";
	private int scheduledCount = 0;
	private int completedCount = 0;

	
	public void logOutput(String output) {
		this.output += output;
	}
	
	public String getOutput() {
		return output;
	}

	private List<TestItem> testItems = new ArrayList<TestItem>();
	
	private GroupDispatcher groupDispatcher;
	private ElevatorControllerInternalConnectionServer internalConnectionServer;
	
	public GroupDispatcher getGroupDispatcher() {
		return groupDispatcher;
	}
	
	public ElevatorControllerInternalConnectionServer getElevatorControllerInternalConnectionServer() {
		return internalConnectionServer;
	}
	
	public TestItemScheduler (GroupDispatcher groupDispatcher, ElevatorControllerInternalConnectionServer internalConnectionServer) {
		this.groupDispatcher = groupDispatcher;
		this.internalConnectionServer = internalConnectionServer;
		
	}
	
	public void schedule(TestItem... testItems) {
		
		for (int i = 0; i < testItems.length; i++) {
			Timer timer = new Timer();
			synchronized (this) {
				scheduledCount++;
			}
			TestItem testItem = testItems[i];
			testItem.setTestItemScheduler(this);
			try {
				timer.schedule(testItem, testItem.getDelay());
			} catch(IllegalStateException e) {
				// some garbage exception
			}
			this.testItems.add(testItem);
		}
		
		
	}
	
	public synchronized void testItemCompleted() {
		completedCount++;
		if (scheduledCount == completedCount) {
			System.out.println("YAY COMPLETED!");
			completed();
		}
	}
	
	private ArrayList<ScheduleCompletedListener> scheduleCompletedListners = new ArrayList<ScheduleCompletedListener>();
	
	private void completed() {
		
		
		
		long hallMin = Long.MAX_VALUE;
		long hallMax = Long.MIN_VALUE;
		long hallTotal = 0;
		int hallCount = 0;
		float hallAvg;
		
		long floorMin = Long.MAX_VALUE;
		long floorMax = Long.MIN_VALUE;
		long floorTotal = 0;
		int floorCount = 0;
		float floorAvg;
		for (TestItem testItem: testItems) {
			if (testItem instanceof HallCallTestItem) {
				if (testItem.getDeltaTime() < hallMin){
					hallMin = testItem.getDeltaTime();
				}
				if (testItem.getDeltaTime() > hallMax) {
					hallMax = testItem.getDeltaTime();
				}
				hallTotal += testItem.getDeltaTime();
				hallCount++;
			}
			
			if (testItem instanceof FloorRequestTestItem) {
				if (testItem.getDeltaTime() < floorMin){
					floorMin = testItem.getDeltaTime();
				}
				if (testItem.getDeltaTime() > floorMax) {
					floorMax = testItem.getDeltaTime();
				}
				floorTotal += testItem.getDeltaTime();
				floorCount++;
			}
		}
		
		hallAvg = (float)hallTotal / hallCount;
		floorAvg = (float)floorTotal / floorCount;
		
		double hallStdTotal = 0;
		double floorStdTotal = 0;
		
		for (TestItem testItem: testItems) {
			if (testItem instanceof HallCallTestItem) {
				hallStdTotal += Math.pow(testItem.getDeltaTime() - hallAvg, 2);
			}
			
			if (testItem instanceof FloorRequestTestItem) {
			
				floorStdTotal += Math.pow(testItem.getDeltaTime() - floorAvg, 2);
			}
		}
		
		double hallStd = Math.sqrt(hallStdTotal / hallCount);
		double floorStd = Math.sqrt(floorStdTotal / floorCount);
		
		
		
		logOutput("\n");
	
		logOutput(String.format("Floor Request Wait Time:\n min/max/avg/std_div %d/%d/%f/%f\n\n", floorMin, floorMax, floorAvg, floorStd));
		logOutput(String.format("Moving Time:\n min/max/avg/std_div %d/%d/%f/%f\n", hallMin, hallMax, hallAvg, hallStd));
		
		for (ScheduleCompletedListener listener: scheduleCompletedListners) {
			listener.scheduleCompleted();
		}
	}

	public void addOnCompletedListener(ScheduleCompletedListener listener) {
		scheduleCompletedListners.add(listener);		
	}
}
